package com.schoolcloud.files.util;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

@Slf4j
public class FFmpegUtil {
    private static final String FFMPEG_PATH = "ffmpeg"; // FFmpeg命令路径，若已配置环境变量可直接使用"ffmpeg"
    private static final String FFPROBE_PATH = "ffprobe"; // FFprobe命令路径，用于获取视频信息

    /**
     * 视频转码为指定格式和编码
     * @param inputPath 输入视频路径
     * @param outputPath 输出视频路径
     * @param format 输出格式（如mp4、flv、webm）
     * @param videoCodec 视频编码（如h264、libx265）
     * @param audioCodec 音频编码（如aac、mp3）
     * @return 转码是否成功
     */
    public static boolean convertVideo(String inputPath, String outputPath, String format, String videoCodec, String audioCodec) {
        List<String> command = new ArrayList<>();
        command.add(FFMPEG_PATH);
        command.add("-i");
        command.add(inputPath);
        command.add("-c:v");
        command.add(videoCodec);
        command.add("-c:a");
        command.add(audioCodec);
        command.add("-y"); // 覆盖已存在文件
        command.add(outputPath);
        return executeCommand(command);
    }

    /**
     * 生成视频截图
     * @param inputPath 输入视频路径
     * @param outputPath 输出截图路径
     * @param time 截图时间点（秒）
     * @param width 截图宽度
     * @param height 截图高度
     * @return 截图是否成功
     */
    public static boolean generateSnapshot(String inputPath, String outputPath, int time, int width, int height) {
        List<String> command = new ArrayList<>();
        command.add(FFMPEG_PATH);
        command.add("-ss");
        command.add(String.valueOf(time));
        command.add("-i");
        command.add(inputPath);
        command.add("-vframes");
        command.add("1");
        command.add("-s");
        command.add(width + "x" + height);
        command.add("-y");
        command.add(outputPath);

        return executeCommand(command);
    }

    /**
     * 视频转码为多分辨率版本（用于HLS流媒体）
     * @param inputPath 输入视频路径
     * @param outputDir 输出目录
     * @param baseName 输出文件基础名称
     * @param resolutions 要生成的分辨率列表（如720p、480p、360p）
     * @return 转码是否成功
     */
    public static boolean convertToMultiResolutions(String inputPath, String outputDir, String baseName, List<String> resolutions) {
        List<String> command = new ArrayList<>();
        command.add(FFMPEG_PATH);
        command.add("-i");
        command.add(inputPath);

        // 为每个分辨率添加输出流
        for (String resolution : resolutions) {
            command.add("-map");
            command.add("0");
            command.add("-s:" + resolutions.indexOf(resolution));
            command.add(resolution);
            command.add("-c:a:" + resolutions.indexOf(resolution));
            command.add("aac");
            command.add("-c:v:" + resolutions.indexOf(resolution));
            command.add("libx264");
            command.add("-preset");
            command.add("medium");
            command.add("-crf");
            command.add("23");
        }

        // HLS相关参数
        command.add("-f");
        command.add("hls");
        command.add("-hls_time");
        command.add("4"); // 每个TS片段时长（秒）
        command.add("-hls_list_size");
        command.add("0"); // 保留所有片段
        command.add("-master_pl_name");
        command.add(baseName + ".m3u8");
        command.add(outputDir + baseName + "_%v.m3u8");

        return executeCommand(command);
    }

    /**
     * 获取视频时长（秒）
     * @param inputPath 输入视频路径
     * @return 视频时长，失败时返回-1
     */
    public static long getVideoDuration(String inputPath) {
        List<String> command = new ArrayList<>();
        command.add(FFPROBE_PATH);
        command.add("-v");
        command.add("error");
        command.add("-show_entries");
        command.add("format=duration");
        command.add("-of");
        command.add("default=noprint_wrappers=1:nokey=1");
        command.add(inputPath);
        Process process = null;
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            process = processBuilder.start();

            String output = readProcessOutput(process.getInputStream());
            return (long) Double.parseDouble(output.trim());
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }

    /**
     * 合并多个视频片段
     * @param inputFiles 输入视频文件列表
     * @param outputPath 输出视频路径
     * @return 合并是否成功
     */
    public static boolean mergeVideos(List<String> inputFiles, String outputPath) {
        if (inputFiles == null || inputFiles.isEmpty()) {
            return false;
        }

        // 创建临时文件列表
        String tempFileListPath = "video_list.txt";
        try {
            StringBuilder fileListContent = new StringBuilder();
            for (String file : inputFiles) {
                fileListContent.append("file '").append(file).append("'\n");
            }
            // 写入文件代码省略...

            List<String> command = new ArrayList<>();
            command.add(FFMPEG_PATH);
            command.add("-f");
            command.add("concat");
            command.add("-safe");
            command.add("0");
            command.add("-i");
            command.add(tempFileListPath);
            command.add("-c");
            command.add("copy");
            command.add(outputPath);

            return executeCommand(command);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 执行FFmpeg命令
     * @param command 命令列表
     * @return 执行结果
     */
    private static boolean executeCommand(List<String> command) {
        Process process = null;
        try {
            System.out.println("执行命令: " + String.join(" ", command));
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            process = processBuilder.start();

            // 异步读取标准输出和错误输出
            ExecutorService executor = Executors.newFixedThreadPool(2);
            Process finalProcess = process;
            Future<?> stdOutFuture = executor.submit(() -> printStream( finalProcess.getInputStream(), "INFO"));
            Future<?> stdErrFuture = executor.submit(() -> printStream(finalProcess.getErrorStream(), "ERROR"));

            // 等待命令执行完成
            int exitCode = process.waitFor();

            // 等待输出读取完成
            stdOutFuture.get();
            stdErrFuture.get();
            executor.shutdown();

            return exitCode == 0;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }

    /**
     * 读取进程输出流
     */
    private static String readProcessOutput(InputStream inputStream) throws IOException {
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }
        }
        return output.toString();
    }

    /**
     * 打印流内容（带日志级别）
     */
    private static void printStream(InputStream inputStream, String level) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println("[" + level + "] " + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // 示例：将视频转码为H.264编码的MP4
        boolean success = convertVideo("input.mp4", "output.mp4", "mp4", "libx264", "aac");
        System.out.println("转码结果: " + (success ? "成功" : "失败"));
    }
}
